﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Collections;
using System.IO.Pipes;
using Wiyan.Code.PowerMSNRobotLibrary.Manager;

namespace Wiyan.Code.PowerMSNRobotLibrary.Utility
{
    class CommandLineHelper
    {
        private static CommandLineHelper _commandLineHelper = null;
        private Thread _worker = null;
        private Process _cmd = null;
        private StreamWriter _inputWriter = null;
        private RobotManager.ReplyMessageDelay _messageSender = null;

        public static EventHandler WorkerProcessExitHandler = null;

        private CommandLineHelper()
        {
        }

        public static CommandLineHelper GetInstance()
        {
            if (_commandLineHelper == null)
            {
                _commandLineHelper = new CommandLineHelper();
            }

            return _commandLineHelper;
        }

        public ErrorCode StartWorker(object parameter)
        {
            object[] parameters = parameter as object[];
            if (parameters == null || parameters.Length != 2)
            {
                return ErrorCode.InvalidWorkerThreadParameter;
            }

            _messageSender = RobotManager.GetInstance().MessageASyncSender;

            if (_worker == null)
            {
                // Start new worker thread
                ParameterizedThreadStart ts = new ParameterizedThreadStart(WorkerProc);
                _worker = new Thread(ts);
                _worker.Start(parameter);
            }
            else
            {
                return ErrorCode.WorkerThreadAlreadyStarted;
            }

            return ErrorCode.Success;
        }

        public ErrorCode CloseWorker(object parameter)
        {
            if (_worker == null)
            {
                return ErrorCode.WorkerThreadNotRunning;
            }

            if (_worker.IsAlive == true)
                _worker.Abort();
            _worker = null;

            if (_cmd != null || _cmd.HasExited == false)
            {
                try
                {
                    _cmd.Kill();
                }
                catch (InvalidOperationException)
                {
                    //Already exit, ignore
                }

                _cmd.Close();
                _cmd.Dispose();
                _cmd = null;
            }

            _messageSender = null;
            return ErrorCode.Success;
        }

        public ErrorCode RunCommand(string command, ref string result)
        {
            if (_worker == null || _cmd == null)
            {
                return ErrorCode.WorkerThreadNotRunning;
            }

            try
            {
                _inputWriter.WriteLine(command);
                _inputWriter.Flush();
            }
            catch (Exception )
            {
                return ErrorCode.RedirectionIOFailed;
            }

            return ErrorCode.Success;
        }

        private void CmdOutPutDataReceived(object sender, DataReceivedEventArgs e)
        {
            Debug.WriteLine(e.Data);

            if (_messageSender != null)
            {
                _messageSender.Invoke(this, e.Data);
            }
        }

        private void CmdErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            Debug.WriteLine(e.Data);

            if (_messageSender != null)
            {
                _messageSender.Invoke(this, e.Data);
            }
        }

        public void WorkerProc(object parameter)
        {
            object[] parameters = parameter as object[];

            Debug.WriteLine("Worker thread is started");

            string fileName = parameters[0].ToString();
            if (string.IsNullOrEmpty(fileName) == true)
                fileName = "cmd.exe";

            // Start
            _cmd = new Process();
            _cmd.StartInfo.FileName = fileName;
            _cmd.StartInfo.Arguments = parameters[1].ToString();
            _cmd.StartInfo.UseShellExecute = false;
            _cmd.StartInfo.RedirectStandardOutput = true;
            _cmd.StartInfo.RedirectStandardInput = true;
            _cmd.StartInfo.RedirectStandardError = true;
            _cmd.StartInfo.CreateNoWindow = true;

            if (WorkerProcessExitHandler != null)
            {
                _cmd.Exited += new EventHandler(WorkerProcessExitHandler);
            }

            _cmd.OutputDataReceived += CmdOutPutDataReceived;
            _cmd.ErrorDataReceived += CmdErrorDataReceived;
            _cmd.EnableRaisingEvents = true;

            _cmd.Start();
            _cmd.BeginOutputReadLine();
            _cmd.BeginErrorReadLine();

            _inputWriter = _cmd.StandardInput;
            _inputWriter.AutoFlush = true;

            _cmd.WaitForExit();
            _cmd.Dispose();
            _cmd = null;
        }
    }
}
